Zepto(function ($) {
    var $leftPanel = $('.left-panel');
    var $frameContainer = $('.frames-container');
    var $appFramesTab = $('#application-frames-tab');
    var $allFramesTab = $('#all-frames-tab');
    var $container = $('.details-container');
    var $activeLine = $frameContainer.find('.frame.active');
    var $activeFrame = $container.find('.frame-code.active');
    var $ajaxEditors = $('.editor-link[data-ajax]');
    var $header = $('header');

    $header.on('mouseenter', function () {
        if ($header.find('.exception').height() >= 145) {
            $header.addClass('header-expand');
        }
    });
    $header.on('mouseleave', function () {
        $header.removeClass('header-expand');
    });

    /*
     * add prettyprint classes to our current active codeblock
     * run prettyPrint() to highlight the active code
     * scroll to the line when prettyprint is done
     * highlight the current line
     */
    var renderCurrentCodeblock = function (id) {

        // remove previous codeblocks so we only render the active one
        $('.code-block').removeClass('prettyprint');

        // pass the id in when we can for speed
        if (typeof(id) === 'undefined' || typeof(id) === 'object') {
            var id = /frame\-line\-([\d]*)/.exec($activeLine.attr('id'))[1];
        }

        $('#frame-code-linenums-' + id).addClass('prettyprint');
        $('#frame-code-args-' + id).addClass('prettyprint');

        prettyPrint(highlightCurrentLine);

    };

    /*
     * Highlight the active and neighboring lines for the current frame
     * Adjust the offset to make sure that line is veritcally centered
     */

    var highlightCurrentLine = function () {
        var activeLineNumber = +($activeLine.find('.frame-line').text());
        var $lines = $activeFrame.find('.linenums li');
        var firstLine = +($lines.first().val());

        // We show more code than needed, purely for proper syntax highlighting
        // Let’s hide a big chunk of that code and then scroll the remaining block
        $activeFrame.find('.code-block').first().css({
            maxHeight: 345,
            overflow: 'hidden',
        });

        var $offset = $($lines[activeLineNumber - firstLine - 10]);
        if ($offset.length > 0) {
            $offset[0].scrollIntoView();
        }

        $($lines[activeLineNumber - firstLine - 1]).addClass('current');
        $($lines[activeLineNumber - firstLine]).addClass('current active');
        $($lines[activeLineNumber - firstLine + 1]).addClass('current');

        $container.scrollTop(0);

    };

    /*
     * click handler for loading codeblocks
     */

    $frameContainer.on('click', '.frame', function () {

        var $this = $(this);
        var id = /frame\-line\-([\d]*)/.exec($this.attr('id'))[1];
        var $codeFrame = $('#frame-code-' + id);

        if ($codeFrame) {

            $activeLine.removeClass('active');
            $activeFrame.removeClass('active');

            $this.addClass('active');
            $codeFrame.addClass('active');

            $activeLine = $this;
            $activeFrame = $codeFrame;

            renderCurrentCodeblock(id);

        }

    });

    var clipboard = new Clipboard('.clipboard');
    var showTooltip = function (elem, msg) {
        elem.setAttribute('class', 'clipboard tooltipped tooltipped-s');
        elem.setAttribute('aria-label', msg);
    };

    clipboard.on('success', function (e) {
        e.clearSelection();

        showTooltip(e.trigger, 'Copied!');
    });

    clipboard.on('error', function (e) {
        showTooltip(e.trigger, fallbackMessage(e.action));
    });

    var btn = document.querySelector('.clipboard');

    btn.addEventListener('mouseleave', function (e) {
        e.currentTarget.setAttribute('class', 'clipboard');
        e.currentTarget.removeAttribute('aria-label');
    });

    function fallbackMessage(action) {
        var actionMsg = '';
        var actionKey = (action === 'cut' ? 'X' : 'C');

        if (/Mac/i.test(navigator.userAgent)) {
            actionMsg = 'Press ⌘-' + actionKey + ' to ' + action;
        } else {
            actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action;
        }

        return actionMsg;
    }

    function scrollIntoView($node, $parent) {
        var nodeOffset = $node.offset();
        var nodeTop = nodeOffset.top;
        var nodeBottom = nodeTop + nodeOffset.height;
        var parentScrollTop = $parent.scrollTop();
        var parentHeight = $parent.height();

        if (nodeTop < 0) {
            $parent.scrollTop(parentScrollTop + nodeTop);
        } else if (nodeBottom > parentHeight) {
            $parent.scrollTop(parentScrollTop + nodeBottom - parentHeight);
        }
    }

    $(document).on('keydown', function (e) {
        var applicationFrames = $frameContainer.hasClass('frames-container-application'),
            frameClass = applicationFrames ? '.frame.frame-application' : '.frame';

        if (e.ctrlKey || e.which === 74 || e.which === 75) {
            // CTRL+Arrow-UP/k and Arrow-Down/j support:
            // 1) select the next/prev element
            // 2) make sure the newly selected element is within the view-scope
            // 3) focus the (right) container, so arrow-up/down (without ctrl) scroll the details
            if (e.which === 38 /* arrow up */ || e.which === 75 /* k */) {
                $activeLine.prev(frameClass).click();
                scrollIntoView($activeLine, $leftPanel);
                $container.focus();
                e.preventDefault();
            } else if (e.which === 40 /* arrow down */ || e.which === 74 /* j */) {
                $activeLine.next(frameClass).click();
                scrollIntoView($activeLine, $leftPanel);
                $container.focus();
                e.preventDefault();
            }
        } else if (e.which == 78 /* n */) {
            if ($appFramesTab.length) {
                setActiveFramesTab($('.frames-tab:not(.frames-tab-active)'));
            }
        }
    });

    // Render late enough for highlightCurrentLine to be ready
    renderCurrentCodeblock();

    // Avoid to quit the page with some protocol (e.g. IntelliJ Platform REST API)
    $ajaxEditors.on('click', function (e) {
        e.preventDefault();
        $.get(this.href);
    });

    // Symfony VarDumper: Close the by default expanded objects
    $('.sf-dump-expanded')
        .removeClass('sf-dump-expanded')
        .addClass('sf-dump-compact');
    $('.sf-dump-toggle span').html('&#9654;');

    // Make the given frames-tab active
    function setActiveFramesTab($tab) {
        $tab.addClass('frames-tab-active');

        if ($tab.attr('id') == 'application-frames-tab') {
            $frameContainer.addClass('frames-container-application');
            $allFramesTab.removeClass('frames-tab-active');
        } else {
            $frameContainer.removeClass('frames-container-application');
            $appFramesTab.removeClass('frames-tab-active');
        }
    }

    $('a.frames-tab').on('click', function (e) {
        e.preventDefault();
        setActiveFramesTab($(this));
    });
});
